#include "gathermgr.h"

#include "data/mycachedata.h"
#include "data/myfunc.h"
#include "data/receivedata.h"
//serial
#include "serialport/serialport.h"
//network
#include "netport/netport.h"

//plan
#include "routing/planthread.h"
//data tran to other sys
#include "transport/mysockettran.h"
#include "transport/mysocketsrv.h"
//time up virtual point
#include "transport/virtualpointtimeup.h"
#include "transport/comxfsys.h"

//android require
#ifdef ANDROID
#include "javaSrc/simpleCustomEvent.h"

#include <QtAndroidExtras/QAndroidJniObject>
#include <QAndroidJniEnvironment>
#include<unistd.h>
#endif
//
#include <QDebug>
#include <QPlainTextEdit>
#include <QVBoxLayout>
#include <QScrollBar>
#include <QPalette>

#include <QApplication>
#include <QAction>
#include <QMenu>
#include <QTimer>

#ifdef WIN32
namespace WINSVC{
extern bool g_bRun;
}
#endif

GatherMgrThread::GatherMgrThread(MyCacheData* _mycdata
                                 ,QMap<int,SerialPort*> _serialps
                                 ,QMap<int,NetPort*> _netGathers
                                 ,QMap<int,MySocketTran*> _clients
                                 ,QObject *parent)
    : QThread(parent)
    , mycdata(_mycdata)
    , serialps(_serialps)
    , netGathers(_netGathers)
    , clients(_clients)
    , running(false)
{
    ptr_ReceiveData = ReceiveData::getInstance();
    running = true;
}

GatherMgrThread::~GatherMgrThread()
{
    running=false;
    try{
        this->terminate();
        this->wait();
        this->exit();
        qInfo() << "GatherMgrThread::destroy\n";
    }catch(...){
        qDebug() << "GatherMgrThread::destroy fail\n";
    }
}

void GatherMgrThread::run()
{
    RDS item_r;
    WDS item_s;
    while(running){
        //获取转发服务端,后台服务端下发的数据
        if (ptr_ReceiveData->getFirstRDS(item_r))
        {
            qInfo() << QString("getFirstRDS time(%1),exeType(%2),pID(%3),pType(%4),val(%5)")
                        .arg(PFunc::getCurrentTime())
                        .arg((int)item_r.exeType)
                        .arg(item_r.pID)
                        .arg((int)item_r.pType)
                        .arg(item_r.val,0,'f',3);
            PFrom _pf;
            if (mycdata->getPFrom(item_r.pID, item_r.pType,_pf))
            {
                //分发到各个串口采集点
                QMap<int,SerialPort*>::iterator it = serialps.find(_pf.gid);
                if (it != serialps.end())
                {
                    it.value()->downControl((int)item_r.exeType, _pf.ptype, _pf.pid, item_r.val);
                }
                //分发到各个网口采集点
                QMap<int,NetPort*>::iterator itNet = netGathers.find(_pf.gid);
                if (itNet != netGathers.end()) {
                    itNet.value()->downControl((int)item_r.exeType, _pf.ptype, _pf.pid, item_r.val);
                }
            }
            if (!ptr_ReceiveData->removeFirstRDS())
            {
                qWarning() << QString("removeFirstRDS failed!");
            }
        }
        //将采集数据分发到各个转发线程
        if (ptr_ReceiveData->getFirstWDS(item_s))
        {
            //转发端口
            for (QMap<int,MySocketTran*>::iterator it = clients.begin(); it != clients.end(); it++)
            {
                it.value()->addWDS(item_s);
            }
            //分发到本app的后台服务,gmap.xml to conf and pmap.xml from conf only the different is ip
            mycdata->setValue("127.0.0.1",item_s.pID,item_s.pType,item_s.val);
            if (!ptr_ReceiveData->removeFirstWDS())
            {
                qWarning() << QString("removeFirstWDS failed!");
            }
        }
        this->msleep(10);
    }
    this->exec();
}

////////////////////////////////////////////////////////////////////////
GatherMgr::GatherMgr(QWidget *parent)
    : QWidget(parent)
    , mycdata(NULL)
    , td_view(NULL)
    , ptr_VirtualPointTimeUp(NULL)
    , ptr_ComXFSys(NULL)
    , ptr_PlanThread(NULL)
    , ptr_MySocketSrv(NULL)
    , ptr_GatherMgrThread(NULL)
{
    qInfo() << "GatherMgr TextEdit init";
    td_view = new QPlainTextEdit(this);
    td_view->document()->setMaximumBlockCount(100);
    QPalette p = palette();
    p.setColor(QPalette::Base, Qt::black);
    p.setColor(QPalette::Text, Qt::green);
    td_view->setPalette(p);
    qInfo() << "GatherMgr layout init";
    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(td_view);
    this->setLayout(layout);
    qInfo() << "GatherMgr MyCacheData init";
//    mycdata = MyCacheData::getInstance();
    //def the port for data gather and transmit
//    initGatherChannel();
    //virtual point time up
//    if(mycdata->getTUpVirtualFunc()){
//        ptr_VirtualPointTimeUp = new VirtualPointTimeUp(this);
//        ptr_VirtualPointTimeUp->start();
//    }else{
//        ptr_VirtualPointTimeUp = NULL;
//    }
    //xf tran
//    if(mycdata->getYunFunc()){
//        ptr_ComXFSys = new ComXFSys(this);
//        ptr_ComXFSys->start();
//    }else{
//        ptr_ComXFSys = NULL;
//    }
    //control by regular,condition,plantime
//    ptr_PlanThread = new PlanThread(this);
//    ptr_PlanThread->start();
    //service for the display client
//    ptr_MySocketSrv = new MySocketSrv();
    //thread for the data transfer
//    ptr_GatherMgrThread = new GatherMgrThread(mycdata,serialps,netGathers,clients,this);
//    ptr_GatherMgrThread->start();
    setWindowIcon(QIcon(":/images/ic_launcher.png"));
//    initTray();
}

GatherMgr::~GatherMgr()
{
    qInfo() << "remove SerialPorts";
    QMap<int,SerialPort*>::iterator itp = serialps.begin();
    while (itp!=serialps.end()) {
       itp.value()->deleteLater();
       itp=serialps.erase(itp);
    }
    qInfo() << "remove NetPortds";
    QMap<int,NetPort*>::iterator itn = netGathers.begin();
    while (itn!=netGathers.end()) {
        itn.value()->deleteLater();
        itn=netGathers.erase(itn);
    }
    qInfo() << "remove MySocketTrans";
    QMap<int,MySocketTran*>::iterator itc = clients.end();
    while (itc!=clients.end()) {
        itc.value()->deleteLater();
        itc=clients.erase(itc);
    }
    if(NULL!=ptr_GatherMgrThread){
        delete ptr_GatherMgrThread;
        ptr_GatherMgrThread = NULL;
    }
    if(NULL!=ptr_VirtualPointTimeUp){
        delete ptr_VirtualPointTimeUp;
        ptr_VirtualPointTimeUp = NULL;
    }
    if(NULL!=ptr_PlanThread){
        delete ptr_PlanThread;
        ptr_PlanThread = NULL;
    }
    if(NULL!=ptr_MySocketSrv){
        delete ptr_MySocketSrv;
        ptr_MySocketSrv = NULL;
    }
}

bool GatherMgr::event(QEvent *et)
{
#ifdef ANDROID
    if(et->type() == SimpleCustomEvent::eventType())
    {
        SimpleCustomEvent *sce = (SimpleCustomEvent*)et;
        if(sce->m_arg1 == 1)//msg
        {
            displayMsg(QString("port[%1] ReadData(%2):%3")
                       .arg(sce->m_arg3).arg(sce->m_arg2.length()).arg(sce->m_arg2));
            emit notify_MsgAndroid(sce->m_arg2,sce->m_arg3);
        }
        else if(sce->m_arg1 == 2)//log
        {
            displayMsg(sce->m_arg2);
        }
        else
        {
            displayMsg("unkown_info");
        }
        return true;
    }
#endif
    return QWidget::event(et);
}

void GatherMgr::initGatherChannel()
{
    displayMsg("initGatherChannel start");
    for(QList<Gather>::iterator it = mycdata->commdef.gathers.begin();
        it!=mycdata->commdef.gathers.end(); it++){
        //serial gather
        if(1==it->atts.type)
        {
            QMap<int,SerialPortArg>::iterator itsp = mycdata->commdef.spdefs.find(it->atts.routeID);
            if(itsp==mycdata->commdef.spdefs.end()){
                continue;
            }
            QMap<int,ProtocolDef>::iterator itpd = mycdata->commdef.protodefs.find(it->atts.protolID);
            if(itpd == mycdata->commdef.protodefs.end()){
                continue;
            }
            SerialPort *serialp = new SerialPort(it->atts.id,it->atts.name
                                                 ,itsp.value(),itpd.value(),it->pinfos,this);
            connect(serialp, &SerialPort::logNotify, this, &GatherMgr::displayMsg);
            connect(this, &GatherMgr::notify_MsgAndroid, serialp, &SerialPort::getMsgAndroid);
            serialps.insert(it->atts.id,serialp);
            displayMsg(QString("port gather(%1,%2) add").arg(it->atts.id).arg(it->atts.name));
        }
        //net gather
        if(2==it->atts.type){
            QMap<int, NetPortArg>::iterator itp = mycdata->commdef.netdefs.find(it->atts.routeID);
            if (itp == mycdata->commdef.netdefs.end())
            {
                continue;
            }
            QMap<int, ProtocolDef>::iterator itl = mycdata->commdef.protodefs.find(it->atts.protolID);
            if (itl == mycdata->commdef.protodefs.end())
            {
                continue;
            }
            NetArg _netarg;
            _netarg.ipStr = itp.value().ip;
            _netarg.port = itp.value().port;
            _netarg.type = itp.value().type;
            _netarg.ptype = itp.value().ptype;
            _netarg.heartFlag = itp.value().readHeartTime;
            _netarg.timePush = itp.value().timePush;
            NetPort *ptr_NetPort = new NetPort(it->atts.id, _netarg,itl.value(),it->pinfos,it->atts.controlSleep,this);
            connect(ptr_NetPort, &NetPort::logNotify, this, &GatherMgr::displayMsg);
            netGathers[it->atts.id] = ptr_NetPort;
            ptr_NetPort->start();
            displayMsg(QString("net gather(%1,%2) add").arg(it->atts.id).arg(it->atts.name));
        }
        //down app gather,级联
        if(3==it->atts.type){
            ;
        }
    }
    displayMsg(QString("initGatherChannel end gathers=%1").arg(mycdata->commdef.gathers.size()));

    for (QList<Transmit>::iterator it = mycdata->commdef.trans.begin();
        it != mycdata->commdef.trans.end();it++)
    {
        //串口转发
        if (it->trantype == 1)
        {
            ;
        }
        //网络转发
        if (it->trantype == 2)
        {
            //转发口编号
            QMap<int,NetPortArg>::iterator itp = mycdata->commdef.netdefs.find(it->dtype);
            if (itp == mycdata->commdef.netdefs.end())
            {
                continue;
            }
            //转发协议脚本
            ProtocolDef _protodefs;
            //自定义解析脚本
            if (1==itp.value().type)
            {
                QMap<int,ProtocolDef>::iterator itl = mycdata->commdef.protodefs.find(it->protocoltype);
                if (itl == mycdata->commdef.protodefs.end())
                {
                    continue;
                }
                _protodefs = itl.value();
            }
            //2==itp->second.type,程序内定义了解析,无需加载脚本
            if (PFunc::ipCheck(itp.value().ip))
            {
                NetArg _netarg;
                _netarg.ipStr = itp.value().ip;
                _netarg.port = itp.value().port;
                _netarg.type = itp.value().type;
                _netarg.ptype = itp.value().ptype;
                MySocketTran *m_MySocketTran = new MySocketTran(it->id, _netarg, _protodefs,this);
                clients[it->id] = m_MySocketTran;
                m_MySocketTran->start();
                displayMsg(QString("net tran(%1,%2,%3,%4) add")
                           .arg(it->id).arg(it->dtype)
                           .arg(it->trantype).arg(it->protocoltype));
            }
            else
            {
                qWarning() << QString("the client[%1] ip[%2] port[%3] config error,please check it!")
                            .arg(it->id).arg(itp.value().ip).arg(itp.value().port);
            }
        }
    }
    displayMsg(QString("initGatherChannel end trans=%1").arg(mycdata->commdef.trans.size()));
}

void GatherMgr::displayMsg(QString msg)
{
    td_view->insertPlainText(msg+"\n");
    QScrollBar *bar = td_view->verticalScrollBar();
    bar->setValue(bar->maximum());
}

void GatherMgr::initTray()
{
    // this->setWindowFlags( Qt::CustomizeWindowHint/*Qt::FramelessWindowHint*/ | Qt::WindowMinimizeButtonHint | Qt::WindowStaysOnTopHint | Qt::Tool );
    Qt::WindowFlags flags = 0;
    flags |= Qt::WindowMinMaxButtonsHint;
    flags |= Qt::CustomizeWindowHint;
    this->setWindowFlags(flags);
    // this->setWindowFlags(windowFlags()&~Qt::WindowCloseButtonHint);
    // this->setWindowOpacity(1);
    this->setMouseTracking(true);
    // this->setAttribute(Qt::WA_TranslucentBackground);

    QIcon icon = QIcon(":/images/ic_launcher.png");
    trayIcon = new QSystemTrayIcon(this);
    trayIcon->setIcon(icon);
    trayIcon->setToolTip(tr("sye-pcs-gathercontrol"));
    QString titlec=tr("sye-pcs-gathercontrol");
    QString textc=tr("sye-pcs-gathercontrol-manage");
    trayIcon->show();
    trayIcon->showMessage(titlec,textc,QSystemTrayIcon::Information,5000);

    //添加单/双击鼠标相应
    connect(trayIcon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
            this,SLOT(trayiconActivated(QSystemTrayIcon::ActivationReason)));

    //创建监听行为
    minimizeAction = new QAction(QIcon(":/images/hide.png"),tr("Min(&I)"), this);
    connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
    restoreAction = new QAction(QIcon(":/images/display.png"),tr("Rec(&R)"), this);
    connect(restoreAction, SIGNAL(triggered()), this, SLOT(showMaximized()));

//    helpAction = new QAction(tr("Help(&H)"), this);
    // helpAction->setShortcut(QKeySequence::HelpContents);
//    connect(helpAction, SIGNAL(triggered()), this, SLOT(helpView()));

    quitAction = new QAction(QIcon(":/images/exit.png"),tr("Quit(&Q)"), this);
//    connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
     connect(quitAction, SIGNAL(triggered()), this, SLOT(myquit()));

    //创建右键弹出菜单
    //trayIconMenu = new QMenu(this);
    trayIconMenu = new QMenu((QWidget*)QApplication::desktop());
    trayIconMenu->addAction(minimizeAction);
    trayIconMenu->addAction(restoreAction);
//    trayIconMenu->addAction(helpAction);
    trayIconMenu->addSeparator();
    trayIconMenu->addAction(quitAction);
    trayIcon->setContextMenu(trayIconMenu);
}

void GatherMgr::trayiconActivated(QSystemTrayIcon::ActivationReason reason)
{
    switch (reason)
    {
    case QSystemTrayIcon::Trigger:
        //单击托盘图标
    case QSystemTrayIcon::DoubleClick:
        //双击托盘图标
        this->showMaximized();
        this->raise();
        break;
    default:
        break;
    }
}

void GatherMgr::myquit()
{
#ifdef WIN32
    WINSVC::g_bRun = false;
#endif
    qApp->quit();
}

void GatherMgr::changeEvent ( QEvent * event )
{
     //重点，窗口最小化时隐藏窗口，最小化到托盘
    if(event->type()==QEvent::WindowStateChange)
    {
        //changeEvent会在窗口最小化之前调用，如果不加QTimer，
        //我们把窗口隐藏了，但是Qt还以为窗口正要最小化，这样就会出错
        if(windowState() & Qt::WindowMinimized){
            QTimer::singleShot(0, this, SLOT(hide()));
            // QApplication::alert(trayIcon);
            //利用这个函数，我们就可以获得比如桌面、音乐、缓存等等的默认路径。
            //QString QDesktopServices::storageLocation(StandardLocation type)
            //调用系统默认程序打开链接
            //QDesktopServices::openUrl();
        }
    }
    QWidget::changeEvent(event);
}

void GatherMgr::hideEvent(QHideEvent *event)
{
    //qDebug()<<"hideEvent\n";
    QWidget::hideEvent(event);
};

//void GatherMgr::closeEvent(QCloseEvent *event)
//{
//    //qDebug()<<"closeEvent\n";
//    if (closeEventEnsure()){
//        event->accept();
//    } else {
//        event->ignore();
//    }
//}

//bool GatherMgr::closeEventEnsure(){

//    CloseCheck *m_CloseCheck = new CloseCheck();
//    m_CloseCheck->setAttribute(Qt::WA_DeleteOnClose);

//    if(m_CloseCheck->exec() == QDialog::Accepted){
//        return true;
//    }else
//    {
//        return false;
//    }
//}

void GatherMgr::showMini()  
{  
#ifdef ANDROID
	QAndroidJniObject::callStaticMethod<void>(  
                    "an/qt5/javagather/PL2303HXDSerialPort",  
                    "mini",  
                    "()V");  
#endif
}  
	
void GatherMgr::moveToFront()  
{  
#ifdef ANDROID
    QAndroidJniObject::callStaticMethod<void>(  
                "an/qt5/javagather/PL2303HXDSerialPort",  
                "moveTaskToFrount",  
                "()V");  
#endif
} 
